package com.liang.manage.auth.facade.server.iml;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.liang.bbs.common.constant.RedisConstants;
import com.liang.manage.auth.facade.channel.RocketMqMessageChannel;
import com.liang.manage.auth.facade.dto.org.OrgOutDTO;
import com.liang.manage.auth.facade.dto.project.ProjectDTO;
import com.liang.manage.auth.facade.dto.role.RoleDTO;
import com.liang.manage.auth.facade.dto.role.RoleOutDTO;
import com.liang.manage.auth.facade.dto.user.*;
import com.liang.manage.auth.facade.entity.UserPo;
import com.liang.manage.auth.facade.entity.UserPoExample;
import com.liang.manage.auth.facade.jwt.JwtUtil;
import com.liang.manage.auth.facade.mapper.UserPoMapper;
import com.liang.manage.auth.facade.mapstruct.UserEmailMS;
import com.liang.manage.auth.facade.mapstruct.UserListMS;
import com.liang.manage.auth.facade.mapstruct.UserMS;
import com.liang.manage.auth.facade.server.*;

import com.liang.manage.auth.facade.utils.FileUploadUtils;
import com.liang.manage.auth.facade.utils.ImageUtils;
import com.liang.nansheng.common.auth.RoleSsoDTO;
import com.liang.nansheng.common.auth.UserSsoDTO;
import com.liang.nansheng.common.constant.TimeoutConstants;
import com.liang.nansheng.common.enums.BaseRoleEnum;
import com.liang.nansheng.common.enums.GenderEnum;
import com.liang.nansheng.common.enums.ImageTypeEnum;
import com.liang.nansheng.common.enums.ResponseCode;
import com.liang.nansheng.common.utils.CommonUtils;
import com.liang.nansheng.common.utils.RegularUtils;
import com.liang.nansheng.common.utils.VerifyCodeUtils;
import com.liang.nansheng.common.web.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author
 * @date 2021/4/25 15:21
 */
@Slf4j
@Service
@Component
public class UserServiceImpl implements UserService {
    @Autowired
    private UserPoMapper userPoMapper;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private OrgService orgService;

    @Autowired
    private PermissionsService permissionsService;

    @Autowired
    private ProjectService projectService;

    @Autowired
    private MailService mailService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ImageUtils imageUtils;

    @Autowired
    private FileUploadUtils fileUploadUtils;

    private static final String REDIRECT_FORMAT = "%s?from_url=%s";

    @Value("${sso.user.login.address}")
    private String ssoAddress;

    @Autowired
    private RocketMqMessageChannel channel;

    /**
     * 用户信息初始化
     */
    @PostConstruct
    private void init() {
        UserPoExample example = new UserPoExample();
        // 获取所有合法的用户信息
        List<UserPo> userPos = userPoMapper.selectByExample(example);
        userPos.forEach(userPo -> {
            // 需要将用户ID:名称（id:name）更新到 Redis
            needUpdateUserIdNameToRedis(userPo.getId(), userPo.getName());
        });
    }

    /**
     * 用户登录
     *
     * @param userLoginDTO
     * @return
     */
    @Override
    public UserTokenDTO login(UserLoginDTO userLoginDTO) {
        if (StringUtils.isBlank(userLoginDTO.getName()) || StringUtils.isBlank(userLoginDTO.getPassword())) {
            throw BusinessException.build(ResponseCode.NOT_EXISTS, "参数不合规");
        }
        UserPoExample example = new UserPoExample();
        UserPoExample.Criteria criteria = example.createCriteria();
        criteria.andStateEqualTo(true).andNameEqualTo(userLoginDTO.getName());
        List<UserPo> userPos = userPoMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(userPos)) {
            throw BusinessException.build(ResponseCode.NOT_EXISTS, "用户名不存在");
        }
        String salt = userPos.get(0).getSalt();
        criteria.andPasswordEqualTo(new Sha256Hash(userLoginDTO.getPassword(), salt).toHex());
        if (CollectionUtils.isEmpty(userPoMapper.selectByExample(example))) {
            throw BusinessException.build(ResponseCode.NOT_MATCH, "用户名/密码错误");
        }

        // 生成UserTokenDTO
        UserTokenDTO userTokenDTO = generateUserToken(userPos.get(0).getId(), userLoginDTO.getName());

        // 通过token获取UserSsoDTO
        getUserSsoDTOByToken(userTokenDTO.getToken());

        return userTokenDTO;
    }

    /**
     * 用户注册
     *
     * @param userDTO
     * @return
     */
    @Override
    public UserTokenDTO register(UserDTO userDTO) {
        if (StringUtils.isBlank(userDTO.getName()) || StringUtils.isBlank(userDTO.getPassword()) || userDTO.getOrgId() == null) {
            throw BusinessException.build(ResponseCode.NOT_EXISTS, "参数不合规");
        }
        if (isNameExist(null, userDTO.getName())) {
            throw BusinessException.build(ResponseCode.NAME_EXIST, "该用户已存在");
        }
        // 加盐
        String salt = RandomStringUtils.randomAlphabetic(20);
        userDTO.setSalt(salt);
        userDTO.setPassword(new Sha256Hash(userDTO.getPassword(), salt).toHex());
        userDTO.setState(true);
        LocalDateTime now = LocalDateTime.now();
        userDTO.setCreateTime(now);
        userDTO.setUpdateTime(now);

        UserPo userPo = UserMS.INSTANCE.toPo(userDTO);
        if (userPoMapper.insertSelective(userPo) <= 0) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "注册用户失败");
        }
        // 新增数据的id赋值给userDTO
        userDTO.setId(userPo.getId());

        // 需要将用户ID:名称（id:name）更新到 Redis
        needUpdateUserIdNameToRedis(userPo.getId(), userPo.getName());

        // 生成UserTokenDTO
        UserTokenDTO userTokenDTO = generateUserToken(userDTO.getId(), userDTO.getName());

        // 通过token获取UserSsoDTO
        getUserSsoDTOByToken(userTokenDTO.getToken());

        // 将新注册的用户信息推mq
        channel.send(JSON.toJSONString(userTokenDTO));

        return userTokenDTO;
    }

    @Override
    public UserTokenDTO registerAuth(UserDTO userDTO) {
        return null;
    }

    /**
     * token已过期
     *
     * @param token
     * @return
     */
    @Override
    public Boolean isExpired(String token) {
        String key = RedisConstants.SSO_KEY + getClaim(token) + ":" + token;
        return !redisTemplate.hasKey(key);
    }

    /**
     * 生成UserToken
     *
     * @param userid
     * @param username
     * @return
     */
    @Override
    public UserTokenDTO generateUserToken(Long userid, String username) {
        // 生成签名
        String token = JwtUtil.sign(userid, String.valueOf(System.currentTimeMillis()));
        UserTokenDTO userInfoDTO = new UserTokenDTO();
        userInfoDTO.setUsername(username);
        userInfoDTO.setToken(token);
        return userInfoDTO;
    }

    /**
     * 通过token获取UserSsoDTO
     *
     * @param token
     * @return
     */
    @Override
    public UserSsoDTO getUserSsoDTOByToken(String token) {
        UserDTO userDTO = getById(getClaim(token));
        UserSsoDTO userSsoDTO = new UserSsoDTO();
        // 基础信息
        userSsoDTO.setUserId(userDTO.getId());
        userSsoDTO.setUserName(userDTO.getName());
        // 组织架构
        userSsoDTO.setOrgId(userDTO.getOrgId());
        // 获取角色信息
        List<UserRoleDTO> userRoleDTOS = userRoleService.getByUserIds(Collections.singletonList(userDTO.getId()));
        if (CollectionUtils.isNotEmpty(userRoleDTOS)) {
            List<RoleSsoDTO> roles = userRoleDTOS.stream().map(userRoleDTO -> roleService.getSsoById(userRoleDTO.getRoleId())).collect(Collectors.toList());
            userSsoDTO.setRoles(roles);
        }

        // 用户信息存redis
        String key = RedisConstants.SSO_KEY + userSsoDTO.getUserId() + ":" + token;
        if (!redisTemplate.hasKey(key)) {
            redisTemplate.opsForValue().set(key, token, TimeoutConstants.NS_SSO_TIMEOUT, TimeUnit.SECONDS);
        }

        return userSsoDTO;
    }

    /**
     * 校验Token是否正确
     *
     * @param token
     * @return
     */
    @Override
    public Boolean verifyToken(String token) {
        return JwtUtil.verify(token);
    }

    /**
     * 获取token中的信息
     *
     * @param token
     * @return
     */
    @Override
    public Long getClaim(String token) {
        return JwtUtil.getClaim(token);
    }

    /**
     * 构造登录网址
     *
     * @param referer
     * @return
     */
    @Override
    public String innerLoginUrl(String referer) {
        return String.format(REDIRECT_FORMAT, ssoAddress, referer);
    }

    /**
     * 分页获取用户列表
     *
     * @param userSearchDTO
     * @return
     */
    @Override
    public PageInfo<UserListDTO> getList(UserSearchDTO userSearchDTO) {
        List<Long> userIds = new ArrayList<>();
        if (userSearchDTO.getRoleId() != null) {
            List<UserRoleDTO> userRoleDTO = userRoleService.getByRoleIds(Collections.singletonList(userSearchDTO.getRoleId()));
            userIds = userRoleDTO.stream().map(UserRoleDTO::getUserId).collect(Collectors.toList());
        }

        UserPoExample example = new UserPoExample();
        UserPoExample.Criteria criteria = example.createCriteria();
        if (userSearchDTO.getId() != null) {
            criteria.andIdEqualTo(userSearchDTO.getId());
        }
        if (StringUtils.isNotBlank(userSearchDTO.getName())) {
            criteria.andNameLike("%" + userSearchDTO.getName() + "%");
        }
        if (userSearchDTO.getState() != null) {
            criteria.andStateEqualTo(userSearchDTO.getState());
        }
        if (userSearchDTO.getOrgId() != null) {
            criteria.andOrgIdEqualTo(userSearchDTO.getOrgId());
        }
        if (userSearchDTO.getRoleId() != null) {
            criteria.andIdIn(userIds);
        }
        example.setOrderByClause("`id` desc");

        PageHelper.startPage(userSearchDTO.getCurrent(), userSearchDTO.getSize());
        List<UserPo> userPos = userPoMapper.selectByExample(example);
        PageInfo<UserListDTO> pageInfo = UserListMS.INSTANCE.toPage(new PageInfo<>(userPos));
        // 组织架构和角色构造
        pageInfo.getList().forEach(this::buildUserListDTO);

        return pageInfo;
    }

    @Override
    public List<UserListDTO> getAllList() {
        return null;
    }

    /**
     * 用户登出
     *
     * @param token
     */
    @Override
    public void logout(String token) {
        if (StringUtils.isNotEmpty(token)) {
            String key = RedisConstants.SSO_KEY + getClaim(token) + ":" + token;
            if (redisTemplate.hasKey(key)) {
                // 清除redis中的用户信息
                redisTemplate.delete(key);
            }
        }
    }

    /**
     * 获取所有性别
     *
     * @return
     */
    @Override
    public Map<Integer, String> getGender() {
        Map<Integer, String> map = new HashMap<>();
        for (GenderEnum genderEnum : GenderEnum.values()) {
            map.put(genderEnum.getCode(), genderEnum.getName());
        }
        return map;
    }

    /**
     * 通过id获取用户
     *
     * @param userid
     * @return
     */
    @Override
    public UserDTO getById(Long userid) {
        return UserMS.INSTANCE.toDTO(userPoMapper.selectByPrimaryKey(userid));
    }

    /**
     * 通过id集合获取用户
     *
     * @param userIds
     * @return
     */
    @Override
    public List<UserDTO> getByIds(List<Long> userIds) {
        UserPoExample example = new UserPoExample();
        example.createCriteria().andIdIn(userIds);
        return UserMS.INSTANCE.toDTO(userPoMapper.selectByExample(example));
    }

    /**
     * 通过角色id获取用户
     *
     * @param roleId
     * @return
     */
    @Override
    public List<UserDTO> getListByRoleId(Integer roleId) {
        List<UserRoleDTO> userRoleDTOS = userRoleService.getByRoleIds(Collections.singletonList(roleId));
        List<Long> userIds = userRoleDTOS.stream().map(UserRoleDTO::getUserId).collect(Collectors.toList());

        UserPoExample example = new UserPoExample();
        example.createCriteria().andIdIn(userIds);
        List<UserPo> userPos = userPoMapper.selectByExample(example);

        return UserMS.INSTANCE.toDTO(userPos);
    }

    /**
     * 不是该角色的用户
     *
     * @param roleIds
     * @return
     */
    @Override
    public List<UserDTO> notUserOfThisRole(List<Integer> roleIds) {
        List<UserRoleDTO> userRoleDTOS = userRoleService.getByRoleIds(roleIds);
        List<Long> userIds = userRoleDTOS.stream().map(UserRoleDTO::getUserId).collect(Collectors.toList());

        UserPoExample example = new UserPoExample();
        if (CollectionUtils.isNotEmpty(userIds)) {
            example.createCriteria().andIdNotIn(userIds);
        }
        List<UserPo> userPos = userPoMapper.selectByExample(example);

        return UserMS.INSTANCE.toDTO(userPos);
    }

    /**
     * 更新用户角色/组织架构
     *
     * @param userRoleOrgDTO
     * @param currentUser
     * @return
     */
    @Override
    public Boolean updateUserRolesOrg(UserRoleOrgDTO userRoleOrgDTO, UserSsoDTO currentUser) {
        // 更新用户角色
        userRoleService.updateUserRole(userRoleOrgDTO, currentUser);

        // 更新组织架构
        UserPo userPo = new UserPo();
        if (userRoleOrgDTO.getOrgId() != null) {
            userPo.setOrgId(userRoleOrgDTO.getOrgId());
        }
        userPo.setId(userRoleOrgDTO.getUserId());
        if (userPoMapper.updateByPrimaryKeySelective(userPo) <= 0) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "更新用户角色失败");
        }

        return true;
    }

    /**
     * 变更用户状态
     *
     * @param userStateDTO
     * @return
     */
    @Override
    public Boolean changeStatus(UserStateDTO userStateDTO) {
        UserPo userPo = new UserPo();
        userStateDTO.getIds().forEach(userid -> {
            userPo.setId(userid);
            // 全部启用
            if (userStateDTO.getIsEnableOrIsDisable()) {
                userPo.setState(true);
            } else if (!userStateDTO.getIsEnableOrIsDisable()) {
                userPo.setState(false);
            }
            // 更新状态成功并且是禁止操作时才清除redis中的用户信息
            if (userPoMapper.updateByPrimaryKeySelective(userPo) > 0 && !userStateDTO.getIsEnableOrIsDisable()) {
                // 清除用户redis中的登录信息（模糊匹配）
                String key = RedisConstants.SSO_KEY + userid + "*";
                Set keys = redisTemplate.keys(key);
                redisTemplate.delete(keys);
            }
        });

        return true;
    }

    /**
     * 需要将用户ID:名称（id:name）更新到 Redis
     *
     * @param userId
     */
    @Override
    public void needUpdateUserIdNameToRedis(Long userId, String name) {
        redisTemplate.opsForHash().put(RedisConstants.USER_ID_TO_NAME_KEY, String.valueOf(userId), name);
    }

    /**
     * 从Redis按用户ID获取用户名称
     *
     * @param userid
     * @return
     */
    @Override
    public String getNameByIdFromRedis(Long userid) {
        Object userName = redisTemplate.opsForHash().get(RedisConstants.USER_ID_TO_NAME_KEY, String.valueOf(userid));
        return String.valueOf(userName);
    }

    /**
     * 上传用户头像（更新）
     *
     * @param bytes
     * @param sourceFileName
     * @param currentUser
     * @return
     */
    @Override
    public Boolean uploadUserPicture(byte[] bytes, String sourceFileName, UserSsoDTO currentUser) {
        if (isFileNotTooBig(bytes)) {
            String picture = fileUploadUtils.fileUpload(imageUtils.pictureCut(bytes), sourceFileName, ImageTypeEnum.headPortrait.name());

            UserPo userPo = new UserPo();
            userPo.setId(currentUser.getUserId());
            userPo.setPicture(picture);
            if (userPoMapper.updateByPrimaryKeySelective(userPo) <= 0) {
                throw BusinessException.build(ResponseCode.OPERATE_FAIL, "更新用户头像失败");
            }
        } else {
            throw BusinessException.build(ResponseCode.EXCEED_THE_MAX, "请上传不超过 " + CommonUtils.byteConversion(imageUtils.getFileLength()) + " 的图片!");
        }

        return true;
    }

    /**
     * 获取用户详情
     *
     * @param userid
     * @return
     */
    @Override
    public UserListDTO getUserListById(Long userid) {
        UserPo userPo = userPoMapper.selectByPrimaryKey(userid);
        UserListDTO userListDTO = UserListMS.INSTANCE.toDTO(userPo);
        if (StringUtils.isNotBlank(userListDTO.getBirthday())) {
            userListDTO.setAge(DateUtil.ageOfNow(userListDTO.getBirthday()));
        }
        // 组织架构和角色构造
        buildUserListDTO(userListDTO);

        return userListDTO;
    }

    /**
     * 更新用户基本信息
     *
     * @param userDTO
     * @param currentUser
     * @return
     */
    @Override
    public Boolean updateUserBasicInfo(UserDTO userDTO, UserSsoDTO currentUser) {
        if (StringUtils.isBlank(userDTO.getName()) || userDTO.getOrgId() == null) {
            throw BusinessException.build(ResponseCode.NOT_EXISTS, "参数不合规");
        }
        userDTO.setId(currentUser.getUserId());
        if (isNameExist(userDTO.getId(), userDTO.getName())) {
            throw BusinessException.build(ResponseCode.NAME_EXIST, "该用户已存在");
        }
        userDTO.setIntro(userDTO.getIntro().trim());
        if (userPoMapper.updateByPrimaryKeySelective(UserMS.INSTANCE.toPo(userDTO)) <= 0) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "更新更新个人资料失败");
        }
        // 需要将用户ID:名称（id:name）更新到 Redis
        needUpdateUserIdNameToRedis(userDTO.getId(), userDTO.getName());

        return true;
    }

    /**
     * 发送邮件验证码
     *
     * @param email
     * @param currentUser
     * @return
     */
    @Override
    public Boolean sendEmailVerifyCode(String email, UserSsoDTO currentUser) {
        if (!RegularUtils.isEmail(email)) {
            throw BusinessException.build(ResponseCode.DATA_ILLEGAL, "email不合法");
        }
        // 判断email是否已经绑定
        if (isEmailExist(email)) {
            throw BusinessException.build(ResponseCode.NAME_EXIST, "邮箱已被其他用户绑定");
        }
        String key = RedisConstants.USER_EMAIL_VERIFY_CODE_KEY + currentUser.getUserId() + ":" + email;
        // 检查是否重复获取验证码
        checkRepeatSubmit(key);
        // 生成验证码
        String code = VerifyCodeUtils.generateVerifyCode(6);
        mailService.sendSimpleMail(email, "【南生海棠】", "验证码：" + code + "，用于邮箱绑定。该验证码5分钟内有效，请勿泄露于他人！");
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
        return true;
    }

    /**
     * 发送短信验证码
     *
     * @param phone
     * @param currentUser
     * @return
     * @throws Exception
     */
    @Override
    public Boolean sendSmsVerifyCode(String phone, UserSsoDTO currentUser) {
        if (!RegularUtils.isMobile(phone)) {
            throw BusinessException.build(ResponseCode.DATA_ILLEGAL, "手机号不合法");
        }
        // 判断手机是否已经绑定
        if (isPhoneExist(phone)) {
            throw BusinessException.build(ResponseCode.NAME_EXIST, "手机已被其他用户绑定");
        }
        String key = RedisConstants.USER_PHONE_VERIFY_CODE_KEY + currentUser.getUserId() + ":" + phone;
        // 检查是否重复获取验证码
        checkRepeatSubmit(key);
        // 生成验证码
        String code = VerifyCodeUtils.generateVerifyCode(6);
        SendSmsResponse response = smsService.sendSms(phone, "{\"code\":\"" + code + "\"}");
        if (!"OK".equals(response.getCode())) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "发送短信验证码失败");
        }
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);

        return true;
    }

    /**
     * 绑定邮箱
     *
     * @param userEmailDTO
     * @param currentUser
     * @return
     */
    @Override
    public Boolean bindEmail(UserEmailDTO userEmailDTO, UserSsoDTO currentUser) {
        // 判断email是否已经绑定
        if (isEmailExist(userEmailDTO.getEmail())) {
            throw BusinessException.build(ResponseCode.NAME_EXIST, "邮箱已被其他用户绑定");
        }
        String key = RedisConstants.USER_EMAIL_VERIFY_CODE_KEY + currentUser.getUserId() + ":" + userEmailDTO.getEmail();
        if (!isVerifyCodeCorrect(key, userEmailDTO.getCode())) {
            throw BusinessException.build(ResponseCode.DATA_EXPIRED, "验证码不正确");
        }
        userEmailDTO.setId(currentUser.getUserId());
        userEmailDTO.setPhone(null);
        if (userPoMapper.updateByPrimaryKeySelective(UserEmailMS.INSTANCE.toPo(userEmailDTO)) <= 0) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "绑定邮箱失败");
        }

        return true;
    }

    /**
     * 绑定手机
     *
     * @param userEmailDTO
     * @param currentUser
     * @return
     */
    @Override
    public Boolean bindPhone(UserEmailDTO userEmailDTO, UserSsoDTO currentUser) {
        // 判断手机是否已经绑定
        if (isPhoneExist(userEmailDTO.getPhone())) {
            throw BusinessException.build(ResponseCode.NAME_EXIST, "手机已被其他用户绑定");
        }
        String key = RedisConstants.USER_PHONE_VERIFY_CODE_KEY + currentUser.getUserId() + ":" + userEmailDTO.getPhone();
        if (!isVerifyCodeCorrect(key, userEmailDTO.getCode())) {
            throw BusinessException.build(ResponseCode.DATA_EXPIRED, "验证码不正确");
        }
        userEmailDTO.setId(currentUser.getUserId());
        userEmailDTO.setEmail(null);
        if (userPoMapper.updateByPrimaryKeySelective(UserEmailMS.INSTANCE.toPo(userEmailDTO)) <= 0) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "绑定手机失败");
        }

        return true;
    }

    /**
     * 解绑邮箱
     *
     * @param currentUser
     * @return
     */
    @Override
    public Boolean untieEmail(UserSsoDTO currentUser) {
        UserPo userPo = new UserPo();
        userPo.setId(currentUser.getUserId());
        userPo.setEmail("");
        if (userPoMapper.updateByPrimaryKeySelective(userPo) <= 0) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "解绑邮箱失败");
        }

        return true;
    }

    /**
     * 解绑手机
     *
     * @param currentUser
     * @return
     */
    @Override
    public Boolean untiePhone(UserSsoDTO currentUser) {
        UserPo userPo = new UserPo();
        userPo.setId(currentUser.getUserId());
        userPo.setPhone("");
        if (userPoMapper.updateByPrimaryKeySelective(userPo) <= 0) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "解绑手机失败");
        }

        return true;
    }

    /**
     * 更新密码
     *
     * @param passwordDTO
     * @param currentUser
     * @return
     */
    @Override
    public Boolean updatePassword(UserPasswordDTO passwordDTO, UserSsoDTO currentUser) {
        // 通过userid获取真实密码
        UserDTO userDTO = getById(currentUser.getUserId());
        String oldPassword = new Sha256Hash(passwordDTO.getOldPassword(), userDTO.getSalt()).toHex();
        if (!userDTO.getPassword().equals(oldPassword)) {
            throw BusinessException.build(ResponseCode.NOT_MATCH, "原密码错误");
        }
        String newPassword = new Sha256Hash(passwordDTO.getNewPassword(), userDTO.getSalt()).toHex();
        UserPo userPo = new UserPo();
        userPo.setId(currentUser.getUserId());
        userPo.setPassword(newPassword);
        if (userPoMapper.updateByPrimaryKeySelective(userPo) <= 0) {
            throw BusinessException.build(ResponseCode.OPERATE_FAIL, "更新密码失败");
        }

        return true;
    }

    /**
     * 邮箱判重
     *
     * @param email
     * @return
     */
    @Override
    public Boolean isValidEmail(String email) {
        // 已存在
        if (isEmailExist(email)) {
            throw BusinessException.build(ResponseCode.NAME_EXIST, "邮箱已被其他用户绑定");
        }
        return true;
    }

    /**
     * 手机判重
     *
     * @param phone
     * @return
     */
    @Override
    public Boolean isValidPhone(String phone) {
        // 已存在
        if (isPhoneExist(phone)) {
            throw BusinessException.build(ResponseCode.NAME_EXIST, "手机已被其他用户绑定");
        }
        return true;
    }

    /**
     * 获取新用户
     *
     * @return
     */
    @Override
    public List<UserListDTO> getNewUser() {
        UserPoExample example = new UserPoExample();
        example.createCriteria().andStateEqualTo(true);
        example.setOrderByClause("`id` desc limit 12");
        List<UserPo> userPos = userPoMapper.selectByExample(example);
        return CollectionUtils.isEmpty(userPos) ? Collections.emptyList() : UserListMS.INSTANCE.toDTO(userPos);
    }

    @Override
    public Map<String, Object> uploadCommonPicture(byte[] bytes, String sourceFileName, UserSsoDTO currentUser) {
        return null;
    }

    /**
     * 更新所有用户的基础角色
     */
    @Override
    public void updateAllUserBaseRole() {
        // 基础角色code
        List<String> codes = new ArrayList<>();
        for (BaseRoleEnum baseRoleEnum : BaseRoleEnum.values()) {
            codes.add(baseRoleEnum.getCode());
        }
        List<RoleDTO> roles = roleService.getByCode(codes);
        if (CollectionUtils.isNotEmpty(roles)) {
            roles.forEach(role -> {
                // 不是该角色的用户（每一个基础角色缺失都需要更新）
                List<UserDTO> users = this.notUserOfThisRole(Collections.singletonList(role.getId()));
                users.forEach(user -> {
                    UserRoleOrgDTO userRoleOrgDTO = new UserRoleOrgDTO();
                    userRoleOrgDTO.setUserId(user.getId());
                    List<Integer> oldRoleIds = userRoleService.getByUserIds(Collections.singletonList(user.getId()))
                            .stream().map(UserRoleDTO::getRoleId).collect(Collectors.toList());
                    oldRoleIds.add(role.getId());
                    userRoleOrgDTO.setRoleIds(oldRoleIds);
                    userRoleService.updateUserRole(userRoleOrgDTO, new UserSsoDTO());
                    log.info("需要给用户: 【{}】, 添加基础角色: 【{}】", user.getName(), role.getName());
                });
            });
        }
    }

    @Override
    public Boolean isValidUser(String userName, UserSsoDTO currentUser) {
        return null;
    }

    @Override
    public void insertChatUser(String userName) {

    }

    @Override
    public void insertGroup(String id) {

    }

    /**
     * 判断验证码是否正确
     *
     * @param key  redis的key
     * @param code 验证码
     * @return true:正确，false:错误
     */
    private Boolean isVerifyCodeCorrect(String key, String code) {
        if (redisTemplate.hasKey(key) && String.valueOf(redisTemplate.opsForValue().get(key)).equals(code)) {
            return true;
        }
        return false;
    }

    /**
     * 检查是否重复获取验证码
     *
     * @param key redis的key
     */
    private void checkRepeatSubmit(String key) {
        if (redisTemplate.hasKey(key)) {
            // 到期时间 单位秒
            long expire = redisTemplate.opsForValue().getOperations().getExpire(key);
            throw BusinessException.build(ResponseCode.NAME_EXIST, "请勿重复发送，" + expire / 60 + " 分钟再试");
        }
    }

    /**
     * 组织架构和角色构造
     *
     * @param userListDTO
     */
    private void buildUserListDTO(UserListDTO userListDTO) {
        // 构造组织架构
        List<Map<String, Object>> orgList = new ArrayList<>();
        OrgOutDTO orgOutDTO = orgService.getById(userListDTO.getOrgId());
        List<Integer> list = CommonUtils.stringListToIntegerList(CommonUtils.stringToList(orgOutDTO.getPath().substring(1), "/"));
        AtomicInteger count = new AtomicInteger();
        list.forEach(orgId -> {
            Map<String, Object> orgMap = new HashMap<>();
            OrgOutDTO outDTO = orgService.getById(orgId);
            orgMap.put("index", count.getAndIncrement());
            orgMap.put("code", outDTO.getCode());
            orgMap.put("name", outDTO.getName());
            orgList.add(orgMap);
        });
        userListDTO.setOrg(orgList);
        // 构造角色
        List<RoleOutDTO> roles = new ArrayList<>();
        List<UserRoleDTO> userRoleDTOS = userRoleService.getByUserIds(Collections.singletonList(userListDTO.getId()));
        userRoleDTOS.forEach(userRoleDTO -> {
            RoleOutDTO roleOutDTO = new RoleOutDTO();
            RoleDTO roleDTO = roleService.getById(userRoleDTO.getRoleId());
            ProjectDTO projectDTO = projectService.getById(roleDTO.getProjectId());

            roleOutDTO.setId(roleDTO.getId());
            roleOutDTO.setCode(roleDTO.getCode());
            roleOutDTO.setName(projectDTO.getName() + " / " + roleDTO.getName());
            roleOutDTO.setDescription(roleDTO.getDescription());
            roles.add(roleOutDTO);
        });
        userListDTO.setRoles(roles);
    }

    /**
     * 判断用户是否已经存在
     *
     * @param userId   用户id
     * @param username 用户名
     * @return
     */
    private boolean isNameExist(Long userId, String username) {
        UserPoExample example = new UserPoExample();
        example.createCriteria().andNameEqualTo(username);
        List<UserPo> userPos = userPoMapper.selectByExample(example);
        if (userPos.size() > 1) {
            return true;
        } else if (userPos.size() == 1) {
            // 更新时userId是有值的
            return !userPos.get(0).getId().equals(userId);
        }
        return false;
    }

    /**
     * 判断email是否已经绑定
     *
     * @param email 邮箱
     * @return
     */
    public Boolean isEmailExist(String email) {
        UserPoExample example = new UserPoExample();
        example.createCriteria().andEmailEqualTo(email);
        List<UserPo> userPos = userPoMapper.selectByExample(example);
        if (userPos.size() > 0) {
            return true;
        }
        return false;
    }

    @Override
    public Boolean phoneResetPassword(UserEmailDTO userEmailDTO) {
        return null;
    }

    @Override
    public Boolean emailResetPassword(UserEmailDTO userEmailDTO) {
        return null;
    }

    @Override
    public UserDTO getByPhone(String phone) {
        return null;
    }

    @Override
    public UserDTO getByEmail(String email) {
        return null;
    }

    @Override
    public void updateAllUserDefaultHead() {

    }

    @Override
    public Boolean checkIdempotent(String url, Integer timeout, TimeUnit timeUnit) {
        return null;
    }

    /**
     * 判断手机是否已经绑定
     *
     * @param phone 手机
     * @return
     */
    public Boolean isPhoneExist(String phone) {
        UserPoExample example = new UserPoExample();
        example.createCriteria().andPhoneEqualTo(phone);
        List<UserPo> userPos = userPoMapper.selectByExample(example);
        if (userPos.size() > 0) {
            return true;
        }
        return false;
    }

    /**
     * 文件是否过大
     *
     * @param bytes
     * @return
     */
    private Boolean isFileNotTooBig(byte[] bytes) {
        // 当前文件大小
        long currentFileSize = bytes.length;
        // 上传源文件允许的最大值
        long fileLength = imageUtils.getFileLength();
        if (currentFileSize <= fileLength) {
            return true;
        } else {
            return false;
        }
    }

}